#include <iostream>
#include <vector>

using namespace std;

void show_info(const vector<int>& v)
{
    cout << "size:" << v.size() << ",capacity:" << v.capacity() << endl;
}

void show_vector(const vector<int>& v)
{
    for (auto i = v.begin(); i != v.end(); i++) {
        cout << *i << " ";
    }
    cout << endl;
}
void test_init()
{
#if 0
    /* default init */
    std:vector<int> v1; /*  size 0 capacity 0 */
    show_info(v1);

    /* init with size*/
    std::vector<int> v2(5);/*  size 0 capacity 5 */
    show_info(v2);

    std::vector<int> v3(5,1);/*  size 0 capacity 5 */
    show_info(v3);
#endif

#if 0
    std::vector<int> v4(5,10);
    show_info(v4);
    show_vector(v4);
    std::vector<int> v5(std::move(v4));
    show_info(v4);
    show_vector(v4);
    show_info(v5);
    show_vector(v5);
    /* after move , the original vector is empty */
    /*
        size:5,capacity:5
        10 10 10 10 10
        size:0,capacity:0

        size:5,capacity:5
        10 10 10 10 10
    */
#endif

#if 1
    std::vector<int> v6(5,2);
    cout <<"v6 value:"<<endl;
    show_info(v6);
    show_vector(v6);
    cout <<"v6 after assign value:"<<endl;
    v6.assign(4,1);
    show_info(v6);
    show_vector(v6);

    cout <<"v7 value:"<<endl;
    std::vector<int> v7(6,6);
    show_info(v7);
    show_vector(v7);
    cout <<"v7 after assign value:"<<endl;
    v7.assign(v6.begin(),v6.begin()+4);
    show_info(v7);
    show_vector(v7);
    cout <<"v6 value:"<<endl;
    show_info(v6);
    show_vector(v6);

    /*  assign change size and value but no change capacity */
    /*
        v6 value:
        size:5,capacity:5
        2 2 2 2 2
        v6 after assign value:
        size:4,capacity:5
        1 1 1 1
        v7 value:
        size:6,capacity:6
        6 6 6 6 6 6
        v7 after assign value:
        size:4,capacity:6
        1 1 1 1
        v6 value:
        size:4,capacity:5
        1 1 1 1
    */

#endif
}

void test_push_back()
{
#if 0
    std::vector<int> v1;
    show_info(v1);
    
    /* test the change of size and capacity in the process of push_back*/
    for (int i = 0; i < 10; i++) {
        v1.push_back(i);
        show_info(v1);
    }
    /*
        extern capacity when size > capacity at the time of push_back
        size:0,capacity:0
        size:1,capacity:1
        size:2,capacity:2
        size:3,capacity:4
        size:4,capacity:4
        size:5,capacity:8
        size:6,capacity:8
        size:7,capacity:8
        size:8,capacity:8
        size:9,capacity:16
        size:10,capacity:16
    */
#endif

#if 1
    std::vector<int> v2(6);
    for (int i = 0; i < 7; i++)
    {
        v2.push_back(i);
        show_info(v2);
    }

    /* base before capacity, capacity*2 when extern capacity */
    /*
        size:7,capacity:12
        size:8,capacity:12
        size:9,capacity:12
        size:10,capacity:12
        size:11,capacity:12
        size:12,capacity:12
        size:13,capacity:24
    */
#endif
}

void test_pop_back()
{
#if 1
    std::vector<int> v1 = {1,2,3,4,5};
    show_info(v1);
    show_vector(v1);

    v1.pop_back();
    show_info(v1);
    show_vector(v1);

    v1.pop_back();
    show_info(v1);
    show_vector(v1);

    /*
        only change size but no change capacity
    */

    /*
        size:5,capacity:5
        1 2 3 4 5
        size:4,capacity:5
        1 2 3 4
        size:3,capacity:5
        1 2 3
    */
#endif
}

void test_insert()
{
#if 0
    std::vector<int> v1(5,1);
    show_info(v1);

    v1.insert(v1.begin(),0);
    show_info(v1);
    show_vector(v1);

    v1.insert(v1.begin()+1,2);
    show_info(v1);
    show_vector(v1);

    /* 
        1.insert also touch the rule of twice capacity externing
        2.the postion that inserted is base iterator 
    */
    /*
        size:5,capacity:5
        size:6,capacity:10
        0 1 1 1 1 1 
        size:7,capacity:10
        0 2 1 1 1 1 1
    */
#endif

#if 0
    std::vector<int> v2(7,1);
    show_info(v2);
    
    v2.insert(v2.end(),0);
    show_info(v2);
    show_vector(v2);
    v2.insert(v2.end(),2);
    show_info(v2);
    show_vector(v2);
    
    v2.insert(v2.end()-2,3);
    show_info(v2);
    show_vector(v2);

    /*
        size:7,capacity:7
        size:8,capacity:14
        1 1 1 1 1 1 1 0 
        size:9,capacity:14
        1 1 1 1 1 1 1 0 2 
        1 1 1 1 1 1 1 0 2
        size:10,capacity:14
        1 1 1 1 1 1 1 3 0 2
    */
#endif

#if 1
    std::vector<int> v3(5,1);
    show_info(v3);
    show_vector(v3);

    v3.emplace_back(0);
    show_info(v3);
    show_vector(v3);
    //v3.emplace_front(2);  /* not support*/
    v3.emplace(v3.begin(),0);
    show_info(v3);
    show_vector(v3);
    v3.emplace(v3.begin()+6,0);
    show_info(v3);
    show_vector(v3);
    v3.emplace(v3.begin()+7,0);
    v3.emplace(v3.begin()+8,0);
    v3.emplace(v3.begin()+9,0);
    show_info(v3);
    show_vector(v3);

    /* emplace_back and emplace also touch the rule of twice capacity externing*/
    /*
        size:5,capacity:5
        1 1 1 1 1
        size:6,capacity:10
        1 1 1 1 1 0
        size:7,capacity:10
        0 1 1 1 1 1 0
        size:8,capacity:10
        0 1 1 1 1 1 0 0
        size:11,capacity:20
        0 1 1 1 1 1 0 0 0 0 0
    */
#endif
}

void test_erase()
{
#if 1
    std::vector<int> v1(5,1);
    show_info(v1);

    v1.erase(v1.begin());
    show_info(v1);
    show_vector(v1);

    v1.erase(v1.begin(), v1.begin()+2);
    show_info(v1);
    show_vector(v1);
    
    /* base iterator and not change capacity */
    /*
        size:5,capacity:5
        size:4,capacity:5
        1 1 1 1
        size:2,capacity:5
        1 1
    */
#endif
}

void test_iterator()
{
    std::vector<int> v1 = {1,2,3,4,5};
#if 0
    /* traverse vector by iterater*/
    for (auto i = v1.begin(); i != v1.end(); i++) {
        cout << *i << " ";
    }
    cout << endl;

    /* desvector vector by iterater*/
    for (auto i = v1.rbegin(); i != v1.rend(); i++) {
        cout << *i << " ";
    }
    cout << endl;
    /*
        1 2 3 4 5 
        5 4 3 2 1
    */
#endif

#if 1
    /* const iterater in c++11 */
    /* const iterator to traverse const vector*/
    for (auto i = v1.cbegin(); i != v1.cend(); i++) {
        cout << *i << " ";
    }
    cout << endl;

    for (auto i = v1.crbegin(); i != v1.crend(); i++) {
        cout << *i << " ";
    }
    cout << endl;

    /*
        1 2 3 4 5 
        5 4 3 2 1
    */

    /* const iterator can not change the value of vector */
    //v1.cbegin() = 10;
#endif
}

void test_clear()
{
#if 1
    std::vector<int> v1(5,1);
    show_info(v1);

    v1.clear();
    show_info(v1);
    show_vector(v1);

    /* only change size but not change capacity */
    /*
        size:5,capacity:5
        size:0,capacity:5
        
    */
#endif
}

void test_access()
{
    std::vector<int> v1 = {1,2,3,4,5};
#if 0
    cout << "front:" << v1.front() << endl;
    cout << "back:" << v1.back() << endl;
    cout << "at:" << v1.at(2) << endl;
    cout << "operator[]:" << v1[2] << endl;
    cout << "data:" << v1.data()[2] << endl;
    
    /*
        front:1
        back:6
        at:3
        operator[]:3
        data:3
    */
#endif

#if 1
    cout << "before:" << endl;
    show_vector(v1);
    v1.front() = 0;
    v1.at(1) = 0;
    v1[2] = 0;
    v1.data()[3] = 0;
    v1.back() = 0;
    cout << "after:" << endl;
    show_vector(v1);

    /* access way that above can change the value of vector */
    /*
        before:
        1 2 3 4 5
        after:
        0 0 0 0 0
    */
#endif
}

void test_capacity()
{
    std::vector<int> v1(5,1);

#if 1
    show_info(v1);

    cout << "empty:" << v1.empty() << endl;
    cout << "size:" << v1.size() << endl;
    cout << "capacity:" << v1.capacity() << endl;
    cout << "max_size:" << v1.max_size() << endl;
    
    v1.resize(10);
    show_info(v1);
    
    v1.assign(10,2);
    show_info(v1);
    show_vector(v1);

    v1.reserve(20);
    show_info(v1);
    show_vector(v1);

    v1.resize(10);
    show_info(v1);
    show_vector(v1);

    v1.reserve(5);
    show_info(v1);
    show_vector(v1);
    
    /* resize and reserve can extern data size but can not reduce size and capacity*/
    /*
        size:5,capacity:5
        empty:0
        size:5
        capacity:5
        max_size:2305843009213693951
        resize:
        size:10,capacity:10
        size:10,capacity:10
        2 2 2 2 2 2 2 2 2 2
        reserve:
        size:10,capacity:20
        2 2 2 2 2 2 2 2 2 2
        size:10,capacity:20
        2 2 2 2 2 2 2 2 2 2
        size:10,capacity:20
        2 2 2 2 2 2 2 2 2 2
    */
#endif
}

/*TODO(wqwang): iterator or index invalid condition */
int main()
{
    //test_init();
    //test_push_back();
    //test_pop_back();
    //test_insert();
    //test_erase();
    //test_clear();
    //test_access();
    //test_iterator();
    test_capacity();
    return 0;
}